package com.ncr.travel.airline.shared.configuration.converters;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ncr.travel.tas.configuration.ConfigurationUtils;
import com.ncr.travel.tas.configuration.model.ConfigurationValue;

public class CountryAirportCode {
    
    /**
     * Provides an encapsulation mechanism for the various ISO 3166-1 data elements for a country
     *
     * @author ms185252
     * @version $Revision$
     * @since  <a href="http://jira.sweng.ncr.com/browse/TGAIR-1746">Configuration for international documents</a>
     */
    public class CountryReference {
        /**
         * The ISO 3166-1 three-character code.
         */
        public final String alpha2Code;
        
        /**
         * The ISO 3166-1 two-character code.
         */
        public final String alpha3Code;
        
        /**
         * The country name.
         */
        public final String name;
        
        /**
         * The country's numeric code.
         */
        public final String numericCode;
        
        /**
         * Initializes an instance of <code>CountryReference</code> with the data provided.
         *
         * @param alpha3Code
         * @param alpha2Code
         * @param numericCode
         * @param name
         */
        public CountryReference(String name, String alpha2Code, String alpha3Code, String numericCode) {
            this.alpha2Code = alpha2Code;
            this.alpha3Code = alpha3Code;
            this.name = name;
            this.numericCode = numericCode;
        }
        
    }
	private static final Logger logger = LoggerFactory.getLogger(CountryAirportCode.class);
	
	public static final String ENABLE = "Enable";
	public static final String CHARS_2 = "2chars";
	public static final String DIGITS_3 = "3digits";
	
	protected final Map<String, String> iso3166Alpha2ToAlpha3 = new HashMap<String, String>();
	protected final Map<String, String> iso3166NumericToAlpha3 = new HashMap<String, String>();

	// From alpha-3.
	protected final Map<String, String> iso3166Alpha3ToAlpha2 = new HashMap<String, String>();
    protected final Map<String, String> iso3166Alpha3ToNumeric = new HashMap<String, String>();
    
    /**
     * Defines a lookup reference for country data by ISO 3166-1 3-character code. 
     */
    protected final Map<String, CountryReference> iso3166Alpha3ToReference = new HashMap<String, CountryReference>();
	
	// Airport
	private final Map<String, String> airportCountryMappings = new HashMap<String, String>();
//
//	public CountryAirportCode(ConfigurationValue countryParent) {
//		init(countryParent);
//	}

	public void initializeMappings(ConfigurationValue countryParent){
	    this.airportCountryMappings.clear();
	    this.iso3166Alpha2ToAlpha3.clear();
	    this.iso3166Alpha3ToAlpha2.clear();
	    this.iso3166Alpha3ToNumeric.clear();
	    this.iso3166Alpha3ToReference.clear();
	    this.iso3166NumericToAlpha3.clear();
	    
		Set<ConfigurationValue> v = countryParent.getChildValues();
	
		for(ConfigurationValue c : v){
		    String countryCode_3 = ConfigurationUtils.getString(c.getKeyName());
		    String countryName =  ConfigurationUtils.getString(c.getValue());
	        String countryCode_2 = "";
	        String countryDigit_3 = "";
	        List<String> airportCodes = new ArrayList<String>();
	        boolean countryEnabled = false;
	        boolean airportEnabled = false;
	        
			for(ConfigurationValue item : c.getChildValues()){
			    String keyName = item.getKeyName().toString();
				if(ENABLE.equals(keyName)){
					countryEnabled = ((Boolean) item.getValue()).booleanValue();
				}
				else if(CHARS_2.equals(keyName)){
					countryCode_2 = ConfigurationUtils.getString(item.getValue());
				}
				else if(DIGITS_3.equals(keyName)){
					countryDigit_3 = ConfigurationUtils.getString(item.getValue());
				}
				else {
					for(ConfigurationValue childItem : item.getChildValues()){
						if(ENABLE.equals(childItem.getKeyName().toString())){
							airportEnabled = ((Boolean) childItem.getValue()).booleanValue();
							if(airportEnabled){
								airportCodes.add(keyName);
							}	
						}
					}
				}	
			}
			
			if(countryEnabled){
				addCountry(countryName, countryCode_2, countryCode_3, countryDigit_3);
				for (String airportCode : airportCodes) {
					addAirport(airportCode, countryCode_3);
				}
			}	
		}
		
	}
	
	private void addCountry(String englishName, String alpha2, String alpha3, String numeric) {
		// To alpha-3
		iso3166Alpha2ToAlpha3.put(alpha2, alpha3);
		iso3166NumericToAlpha3.put(numeric, alpha3);

		// From alpha-3.
		iso3166Alpha3ToAlpha2.put(alpha3, alpha2);
		iso3166Alpha3ToNumeric.put(alpha3, numeric);
		CountryReference reference = new CountryReference(englishName, alpha2, alpha3, numeric);
		this.iso3166Alpha3ToReference.put(alpha3, reference);
	}

	private void addAirport(String airport, String alpha3){
		airportCountryMappings.put(airport, alpha3);
	}
	
	public String getAirportCountry(String airportCode) {
		String countryCode = airportCountryMappings.get(airportCode);
		if (countryCode == null) {
			logger.warn("Airport \"" + airportCode + "\" is not mapped to a country.");
		}

		return countryCode;
	}
	
	/**
	 * @param alpha3Code
	 * @return
	 */
	public String convertIsoAlpha3ToAlpha2(String alpha3Code) {
		String result = iso3166Alpha3ToAlpha2.get(alpha3Code);
		if (result == null) {
			logger.warn("Unmapped ISO 3166-1 alpha-3 code: " + alpha3Code);
		}

		return result;
	}

	public String convertIsoAlpha2ToAlpha3(String alpha2Code) {
		String result = iso3166Alpha2ToAlpha3.get(alpha2Code);
		if (result == null) {
			logger.warn("Unmapped ISO 3166-1 alpha-2 code: " + alpha2Code);
		}
		return result;
	}

	/**
	 * Obtains all references to enabled country information.
	 * 
	 * @return all enabled country reference data
	 */
	public Collection<CountryReference> getCountryReferences() {
	    return this.iso3166Alpha3ToReference.values();
	}


    /**
     * Obtains the reference matching the provided country code.
     * 
     * @param alpha3Code the three-character code to look up
     * @return the matching reference, or null if the country code is disabled or not mapped
     */
    public CountryReference getCountryReference(String alpha3Code) {
        CountryReference result = this.iso3166Alpha3ToReference.get(alpha3Code);
        if (result == null) {
            logger.warn("Data for ISO 3166-1 alpha-3 code {} is unavailable", alpha3Code);
        }
        return result;
    }
	
}
